#ifndef __RTMP_H__
#define __RTMP_H__
/*
 *      Copyright (C) 2005-2008 Team XBMC
 *      http://www.xbmc.org
 *      Copyright (C) 2008-2009 Andrej Stepanchuk
 *      Copyright (C) 2009-2010 Howard Chu
 *
 *  This file is part of librtmp.
 *
 *  librtmp is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1,
 *  or (at your option) any later version.
 *
 *  librtmp is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with librtmp see the file COPYING.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301, USA.
 *  http://www.gnu.org/copyleft/lgpl.html
 */

#if !defined(NO_CRYPTO) && !defined(CRYPTO)
#define CRYPTO
#endif

#include <errno.h>
#include "stdint.h"
#include <stddef.h>

#include "amf.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define RTMP_LIB_VERSION	0x020300	/* 2.3 */

#define RTMP_FEATURE_HTTP	0x01
#define RTMP_FEATURE_ENC	0x02
#define RTMP_FEATURE_SSL	0x04
#define RTMP_FEATURE_MFP	0x08	/* not yet supported */
#define RTMP_FEATURE_WRITE	0x10	/* publish, not play */
#define RTMP_FEATURE_HTTP2	0x20	/* server-side rtmpt */

#define RTMP_PROTOCOL_UNDEFINED	-1
#define RTMP_PROTOCOL_RTMP      0
#define RTMP_PROTOCOL_RTMPE     RTMP_FEATURE_ENC
#define RTMP_PROTOCOL_RTMPT     RTMP_FEATURE_HTTP
#define RTMP_PROTOCOL_RTMPS     RTMP_FEATURE_SSL
#define RTMP_PROTOCOL_RTMPTE    (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC)
#define RTMP_PROTOCOL_RTMPTS    (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL)
#define RTMP_PROTOCOL_RTMFP     RTMP_FEATURE_MFP

#define RTMP_DEFAULT_CHUNKSIZE	128

/* needs to fit largest number of bytes recv() may return */
#define RTMP_BUFFER_CACHE_SIZE (16*1024)

#define	RTMP_CHANNELS	65600

extern const char RTMPProtocolStringsLower[][7];
extern const AVal RTMP_DefaultFlashVer;
extern int RTMP_ctrlC;

uint32_t RTMP_GetTime ( void );

/*      RTMP_PACKET_TYPE_...                0x00 */
#define RTMP_PACKET_TYPE_CHUNK_SIZE         0x01
/*      RTMP_PACKET_TYPE_...                0x02 */
#define RTMP_PACKET_TYPE_BYTES_READ_REPORT  0x03
#define RTMP_PACKET_TYPE_CONTROL            0x04
#define RTMP_PACKET_TYPE_SERVER_BW          0x05
#define RTMP_PACKET_TYPE_CLIENT_BW          0x06
/*      RTMP_PACKET_TYPE_...                0x07 */
#define RTMP_PACKET_TYPE_AUDIO              0x08
#define RTMP_PACKET_TYPE_VIDEO              0x09
/*      RTMP_PACKET_TYPE_...                0x0A */
/*      RTMP_PACKET_TYPE_...                0x0B */
/*      RTMP_PACKET_TYPE_...                0x0C */
/*      RTMP_PACKET_TYPE_...                0x0D */
/*      RTMP_PACKET_TYPE_...                0x0E */
#define RTMP_PACKET_TYPE_FLEX_STREAM_SEND   0x0F
#define RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT 0x10
#define RTMP_PACKET_TYPE_FLEX_MESSAGE       0x11
#define RTMP_PACKET_TYPE_INFO               0x12
#define RTMP_PACKET_TYPE_SHARED_OBJECT      0x13
#define RTMP_PACKET_TYPE_INVOKE             0x14
/*      RTMP_PACKET_TYPE_...                0x15 */
#define RTMP_PACKET_TYPE_FLASH_VIDEO        0x16

#define RTMP_MAX_HEADER_SIZE 18

#define RTMP_PACKET_SIZE_LARGE    0
#define RTMP_PACKET_SIZE_MEDIUM   1
#define RTMP_PACKET_SIZE_SMALL    2
#define RTMP_PACKET_SIZE_MINIMUM  3

typedef struct RTMPChunk
{
	int c_headerSize;
	int c_chunkSize;
	char *c_chunk;
	char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;

typedef struct RTMPPacket
{
	uint8_t m_headerType;
	uint8_t m_packetType;
	uint8_t m_hasAbsTimestamp;	/* timestamp absolute or relative? */
	int m_nChannel;
	uint32_t m_nTimeStamp;	/* timestamp */
	int32_t m_nInfoField2;	/* last 4 bytes in a long header */
	uint32_t m_nBodySize;
	uint32_t m_nBytesRead;
	RTMPChunk *m_chunk;
	char *m_body;
} RTMPPacket;

typedef struct RTMPSockBuf
{
	int sb_socket;
	int sb_size;		/* number of unprocessed bytes in buffer */
	char *sb_start;		/* pointer into sb_pBuffer of next byte to process */
	char sb_buf[RTMP_BUFFER_CACHE_SIZE];	/* data read from socket */
	int sb_timedout;
	void *sb_ssl;
} RTMPSockBuf;

void RTMPPacket_Reset ( RTMPPacket *p );
void RTMPPacket_Dump ( RTMPPacket *p );
int RTMPPacket_Alloc ( RTMPPacket *p, int nSize );
void RTMPPacket_Free ( RTMPPacket *p );

#define RTMPPacket_IsReady(a)	((a)->m_nBytesRead == (a)->m_nBodySize)

typedef struct RTMP_LNK
{
	AVal hostname;
	AVal sockshost;

	AVal playpath0;	/* parsed from URL */
	AVal playpath;	/* passed in explicitly */
	AVal tcUrl;
	AVal swfUrl;
	AVal pageUrl;
	AVal app;
	AVal auth;
	AVal flashVer;
	AVal subscribepath;
	AVal usherToken;
	AVal token;
	AVal pubUser;
	AVal pubPasswd;
	AMFObject extras;
	int edepth;

	int seekTime;
	int stopTime;

#define RTMP_LF_AUTH	0x0001	/* using auth param */
#define RTMP_LF_LIVE	0x0002	/* stream is live */
#define RTMP_LF_SWFV	0x0004	/* do SWF verification */
#define RTMP_LF_PLST	0x0008	/* send playlist before play */
#define RTMP_LF_BUFX	0x0010	/* toggle stream on BufferEmpty msg */
#define RTMP_LF_FTCU	0x0020	/* free tcUrl on close */
#define RTMP_LF_FAPU	0x0040	/* free app on close */
	int lFlags;

	int swfAge;

	int protocol;
	int timeout;		/* connection timeout in seconds */

	int pFlags;

	unsigned short socksport;
	unsigned short port;

#ifdef CRYPTO
#define RTMP_SWF_HASHLEN	32
	void *dh;			/* for encryption */
	void *rc4keyIn;
	void *rc4keyOut;

	uint32_t SWFSize;
	uint8_t SWFHash[RTMP_SWF_HASHLEN];
	char SWFVerificationResponse[RTMP_SWF_HASHLEN + 10];
#endif
} RTMP_LNK;

/* state for read() wrapper */
typedef struct RTMP_READ
{
	char *buf;
	char *bufpos;
	unsigned int buflen;
	uint32_t timestamp;
	uint8_t dataType;
	uint8_t flags;
#define RTMP_READ_HEADER	0x01
#define RTMP_READ_RESUME	0x02
#define RTMP_READ_NO_IGNORE	0x04
#define RTMP_READ_GOTKF		0x08
#define RTMP_READ_GOTFLVK	0x10
#define RTMP_READ_SEEKING	0x20
	int8_t status;
#define RTMP_READ_COMPLETE	-3
#define RTMP_READ_ERROR	-2
#define RTMP_READ_EOF	-1
#define RTMP_READ_IGNORE	0

	/* if bResume == TRUE */
	uint8_t initialFrameType;
	uint32_t nResumeTS;
	char *metaHeader;
	char *initialFrame;
	uint32_t nMetaHeaderSize;
	uint32_t nInitialFrameSize;
	uint32_t nIgnoredFrameCounter;
	uint32_t nIgnoredFlvFrameCounter;
} RTMP_READ;

typedef struct RTMP_METHOD
{
	AVal name;
	int num;
} RTMP_METHOD;

typedef struct RTMP
{
	int m_inChunkSize;
	int m_outChunkSize;
	int m_nBWCheckCounter;
	int m_nBytesIn;
	int m_nBytesInSent;
	int m_nBufferMS;
	int m_stream_id;		/* returned in _result from createStream */
	int m_mediaChannel;
	uint32_t m_mediaStamp;
	uint32_t m_pauseStamp;
	int m_pausing;
	int m_nServerBW;
	int m_nClientBW;
	uint8_t m_nClientBW2;
	uint8_t m_bPlaying;
	uint8_t m_bSendEncoding;
	uint8_t m_bSendCounter;

	int m_numInvokes;
	int m_numCalls;
	RTMP_METHOD *m_methodCalls;	/* remote method calls queue */

	int m_channelsAllocatedIn;
	int m_channelsAllocatedOut;
	RTMPPacket **m_vecChannelsIn;
	RTMPPacket **m_vecChannelsOut;
	int *m_channelTimestamp;	/* abs timestamp of last packet */

	double m_fAudioCodecs;	/* audioCodecs for the connect packet */
	double m_fVideoCodecs;	/* videoCodecs for the connect packet */
	double m_fEncoding;		/* AMF0 or AMF3 */

	double m_fDuration;		/* duration of stream in seconds */

	int m_msgCounter;		/* RTMPT stuff */
	int m_polling;
	int m_resplen;
	int m_unackd;
	AVal m_clientID;

	RTMP_READ m_read;
	RTMPPacket m_write;
	RTMPSockBuf m_sb;
	RTMP_LNK Link;
} RTMP;

int RTMP_ParseURL ( const char *url, int *protocol, AVal *host,
					unsigned int *port, AVal *playpath, AVal *app );

void RTMP_ParsePlaypath ( AVal *in, AVal *out );
void RTMP_SetBufferMS ( RTMP *r, int size );
void RTMP_UpdateBufferMS ( RTMP *r );

int RTMP_SetOpt ( RTMP *r, const AVal *opt, AVal *arg );
int RTMP_SetupURL ( RTMP *r, char *url );
void RTMP_SetupStream ( RTMP *r, int protocol,
						AVal *hostname,
						unsigned int port,
						AVal *sockshost,
						AVal *playpath,
						AVal *tcUrl,
						AVal *swfUrl,
						AVal *pageUrl,
						AVal *app,
						AVal *auth,
						AVal *swfSHA256Hash,
						uint32_t swfSize,
						AVal *flashVer,
						AVal *subscribepath,
						AVal *usherToken,
						int dStart,
						int dStop, int bLiveStream, long int timeout );

int RTMP_Connect ( RTMP *r, RTMPPacket *cp );
struct sockaddr;
int RTMP_Connect0 ( RTMP *r, struct sockaddr *svc );
int RTMP_Connect1 ( RTMP *r, RTMPPacket *cp );
int RTMP_Serve ( RTMP *r );
int RTMP_TLS_Accept ( RTMP *r, void *ctx );

int RTMP_ReadPacket ( RTMP *r, RTMPPacket *packet );
int RTMP_SendPacket ( RTMP *r, RTMPPacket *packet, int queue );
int RTMP_SendChunk ( RTMP *r, RTMPChunk *chunk );
int RTMP_IsConnected ( RTMP *r );
int RTMP_Socket ( RTMP *r );
int RTMP_IsTimedout ( RTMP *r );
double RTMP_GetDuration ( RTMP *r );
int RTMP_ToggleStream ( RTMP *r );

int RTMP_ConnectStream ( RTMP *r, int seekTime );
int RTMP_ReconnectStream ( RTMP *r, int seekTime );
void RTMP_DeleteStream ( RTMP *r );
int RTMP_GetNextMediaPacket ( RTMP *r, RTMPPacket *packet );
int RTMP_ClientPacket ( RTMP *r, RTMPPacket *packet );

void RTMP_Init ( RTMP *r );
void RTMP_Close ( RTMP *r );
RTMP *RTMP_Alloc ( void );
void RTMP_Free ( RTMP *r );
void RTMP_EnableWrite ( RTMP *r );

void *RTMP_TLS_AllocServerContext ( const char *cert, const char *key );
void RTMP_TLS_FreeServerContext ( void *ctx );

int RTMP_LibVersion ( void );
void RTMP_UserInterrupt ( void );	/* user typed Ctrl-C */

int RTMP_SendCtrl ( RTMP *r, short nType, unsigned int nObject,
					unsigned int nTime );

/* caller probably doesn't know current timestamp, should
 * just use RTMP_Pause instead
 */
int RTMP_SendPause ( RTMP *r, int DoPause, int dTime );
int RTMP_Pause ( RTMP *r, int DoPause );

int RTMP_FindFirstMatchingProperty ( AMFObject *obj, const AVal *name,
									 AMFObjectProperty *p );

int RTMPSockBuf_Fill ( RTMPSockBuf *sb );
int RTMPSockBuf_Send ( RTMPSockBuf *sb, const char *buf, int len );
int RTMPSockBuf_Close ( RTMPSockBuf *sb );

int RTMP_SendCreateStream ( RTMP *r );
int RTMP_SendSeek ( RTMP *r, int dTime );
int RTMP_SendServerBW ( RTMP *r );
int RTMP_SendClientBW ( RTMP *r );
void RTMP_DropRequest ( RTMP *r, int i, int freeit );
int RTMP_Read ( RTMP *r, char *buf, int size );
int RTMP_Write ( RTMP *r, const char *buf, int size );

/* hashswf.c */
int RTMP_HashSWF ( const char *url, unsigned int *size, unsigned char *hash,
				   int age );

#ifdef __cplusplus
};
#endif

#endif
